package com.acme.bankapp.dal;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.acme.bankapp.domain.account.Account;
import com.acme.bankapp.domain.account.CheckingAccount;
import com.acme.bankapp.domain.account.SavingAccount;
import com.acme.bankapp.domain.client.Client;
import com.acme.bankapp.domain.client.Gender;

public class ClientFeedDAO {

	private static final String ERR_OVERDRAFT_FIELD_MISSING = "overdraft field is missing";
	private static final String REGEX_PARSE_CSV = "^accounttype=(c|s);balance=([\\d\\.]+);(overdraft=([\\d\\.]+);)?name=([^;]+);gender=(m|f);$";

	public static List<Client> getAllClientsFromFeed(final InputStream source) throws IOException, InvalidFeedFormatException {

		List<Client> clients = new ArrayList<>();
		for (String line : readAllStringsFromStream(source)) {
			clients.add(createClientFromCSV(line));
		}

		return clients;
	}

	public static Client createClientFromCSV(String csv)
			throws InvalidFeedFormatException {

		Pattern pattern = Pattern.compile(REGEX_PARSE_CSV);
		Matcher matcher = pattern.matcher(csv);

		if (!matcher.matches())
			throw new InvalidFeedFormatException();

		String accounttype = matcher.group(1);

		double balance;
		double overdraft;
		try {
			balance = Double.parseDouble(matcher.group(2));
			overdraft = 0;
			if ("c".equals(accounttype))
				overdraft = Double.parseDouble(matcher.group(4));
		} catch (NumberFormatException e) {
			throw new InvalidFeedFormatException(e);
		} catch (NullPointerException e) {
			throw new InvalidFeedFormatException(ERR_OVERDRAFT_FIELD_MISSING, e);
		}

		String name = matcher.group(5);
		Gender gender = "m".equals(matcher.group(6)) ? Gender.MALE
				: Gender.FEMALE;

		Account account;
		if ("c".equals(accounttype)) {
			account = new CheckingAccount(balance, overdraft);
		} else {
			account = new SavingAccount(balance);
		}

		return new Client(name, gender, account);
	}

	private static List<String> readAllStringsFromStream(final InputStream stream)
			throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(stream));
		List<String> list = new ArrayList<>();
		
		try {
			String line;
			while ((line = br.readLine()) != null) {
				list.add(line);
			}
		} finally {
			br.close();
		}
		
		return list;
	}

}
